/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#include "RichTextEdit.h"

#include <QtCore/QtDebug>
#include <QtCore/QModelIndex>
#include <QtCore/QAbstractItemModel>

#include <QtGUI/QCompleter>
#include <QtGUI/QKeyEvent>
#include <QtGUI/QAbstractItemView>
#include <QtGUI/QApplication>
#include <QtGUI/QScrollBar>

namespace QSThink
{
	RichTextEdit::RichTextEdit(QWidget *parent)
	: QTextEdit(parent), _completer(0)
	{
		setPlainText(tr("This TextEdit provides autocompletions for words that have more than"
						" 3 characters. You can trigger autocompletion using ") + 
						QKeySequence("Ctrl+E").toString(QKeySequence::NativeText));
	}

	RichTextEdit::~RichTextEdit()
	{
	}

	void RichTextEdit::setCompleter(QCompleter *completer)
	{
		if (_completer){
			QObject::disconnect(_completer, 0, this, 0);
		}

		_completer = completer;

		if (!_completer){
			return;
		}

		_completer->setWidget(this);
		_completer->setCompletionMode(QCompleter::PopupCompletion);
		_completer->setCaseSensitivity(Qt::CaseInsensitive);
		QObject::connect(_completer, SIGNAL(activated(QString)),
						 this, SLOT(insertCompletion(QString)));
	}

	QCompleter *RichTextEdit::completer() const
	{
		return _completer;
	}

	void RichTextEdit::insertCompletion(const QString& completion)
	{
		if (_completer->widget() != this){
			return;
		}

		QTextCursor tc = textCursor();
		int extra = completion.length() - _completer->completionPrefix().length();
		tc.movePosition(QTextCursor::Left);
		tc.movePosition(QTextCursor::EndOfWord);
		tc.insertText(completion.right(extra));
		setTextCursor(tc);
	}

	QString RichTextEdit::textUnderCursor() const
	{
		QTextCursor tc = textCursor();
		tc.select(QTextCursor::WordUnderCursor);
		return tc.selectedText();
	}

	void RichTextEdit::focusInEvent(QFocusEvent *e)
	{
		if (_completer){
			_completer->setWidget(this);
		}

		QTextEdit::focusInEvent(e);
	}

	void RichTextEdit::keyPressEvent(QKeyEvent *e)
	{
		if (_completer && _completer->popup()->isVisible()) {
			// The following keys are forwarded by the completer to the widget
		   switch (e->key()) {
		   case Qt::Key_Enter:
		   case Qt::Key_Return:
		   case Qt::Key_Escape:
		   case Qt::Key_Tab:
		   case Qt::Key_Backtab:
				e->ignore(); 
				return; // let the completer do default behavior
		   default:
			   break;
		   }
		}

		bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
		if (!_completer || !isShortcut){ // dont process the shortcut when we have a completer}
			QTextEdit::keyPressEvent(e);
		}

		const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
		if (!_completer || (ctrlOrShift && e->text().isEmpty()))
			return;

		static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
		bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
		QString completionPrefix = textUnderCursor();

		if (!isShortcut &&

			(hasModifier || 
			e->text().isEmpty()|| 
			completionPrefix.length() < 3 || 
			eow.contains(e->text().right(1)))

			) {
			_completer->popup()->hide();
			return;
		}

		if (completionPrefix != _completer->completionPrefix()) {
			_completer->setCompletionPrefix(completionPrefix);
			_completer->popup()->setCurrentIndex(_completer->completionModel()->index(0, 0));
		}

		QRect cr = cursorRect();
		cr.setWidth(_completer->popup()->sizeHintForColumn(0)
					+ _completer->popup()->verticalScrollBar()->sizeHint().width());
		_completer->complete(cr); // popup it up!
	}

}
